package hc.server.ui.design;

import hc.App;
import hc.core.IConstant;
import hc.core.RootConfig;
import hc.core.util.StringUtil;
import hc.res.ImageSrc;
import hc.server.FileSelector;
import hc.server.J2SEContext;
import hc.server.SingleJFrame;
import hc.server.ThirdlibManager;
import hc.server.ui.ServerUIUtil;
import hc.server.ui.design.hpj.HCShareFileResource;
import hc.server.ui.design.hpj.HCjar;
import hc.server.ui.design.hpj.HPItemContext;
import hc.server.ui.design.hpj.HPNode;
import hc.server.ui.design.hpj.HPShareJRubyFolder;
import hc.server.ui.design.hpj.HPShareJarFolder;
import hc.server.ui.design.hpj.HPShareRoot;
import hc.server.ui.design.hpj.IModifyStatus;
import hc.server.ui.design.hpj.MenuManager;
import hc.server.ui.design.hpj.NodeEditPanel;
import hc.server.ui.design.hpj.NodeEditPanelManager;
import hc.server.ui.design.hpj.NodeInvalidException;
import hc.util.PropertiesManager;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
import javax.swing.ToolTipManager;
import javax.swing.border.TitledBorder;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

public class Designer extends SingleJFrame implements IModifyStatus{
	public static final String MY_DEPLOY_PROJ = "myproj.jar";
	public static final String MY_EDIT_PROJ = "myedit.jar";
	
	public static final String MY_DEPLOY_PROJ_HAR = "myproj.har";
	public static final String MY_EDIT_PROJ_HAR = "myedit.har";
	
	public static ImageIcon loadImg(String path){
		try {
			return new ImageIcon(ImageIO.read(Designer.class.getClassLoader().getResource(path)));
		} catch (IOException e) {
			return null;
		}
	}
	static {
		ToolTipManager.sharedInstance().setDismissDelay(1000 * 20);
	}

	@Override
	public void updateSkinUI(){
		super.updateSkinUI();
		
		mm.updateSkinUI();
		nm.updateSkinUI();
		
		tree.updateUI();
	}
	
	private boolean isModified;
	MenuManager mg = new MenuManager();

	JTree tree;
	// 上面JTree对象对应的model
	DefaultTreeModel model;

	// 定义几个初始节点
	DefaultMutableTreeNode root = createNewRoot();
	public static final int ROOT_SUB_FOLDER = 2;
	final DefaultMutableTreeNode[] shareFolders = new DefaultMutableTreeNode[ROOT_SUB_FOLDER];

	private DefaultMutableTreeNode createShareJRubyFolder() {
		HPShareJRubyFolder sj = new HPShareJRubyFolder(HPNode.MASK_SHARE_RB_FOLDER, 
				"Share JRuby Files");
		return new DefaultMutableTreeNode(sj);
	}
	
	private DefaultMutableTreeNode createShareJarFolder() {
		HPShareJarFolder sj = new HPShareJarFolder(HPNode.MASK_RESOURCE_FOLDER_JAR, 
				"Share Jar Files");
		return new DefaultMutableTreeNode(sj);
	}
	
	private DefaultMutableTreeNode createNewRoot() {
		return new DefaultMutableTreeNode(new HPNode(
				HPNode.MASK_ROOT, "Project"));
	}
//	DefaultMutableTreeNode guangdong = new DefaultMutableTreeNode(new HPItem(
//			HPItem.MASK_MENU, "firstMenu"));
//	DefaultMutableTreeNode guangxi = new DefaultMutableTreeNode(new HPItem(
//			HPItem.MASK_MENU, "广西"));
//	DefaultMutableTreeNode foshan = new DefaultMutableTreeNode(
//			new HPMenuItem(HPItem.TYPE_MENU_ITEM_SCREEN, "关机", "screen://home", ""));
//	DefaultMutableTreeNode shantou = new DefaultMutableTreeNode(
//			new HPMenuItem(HPItem.TYPE_MENU_ITEM_CMD, "退出", "cmd://exit", ""));
//	DefaultMutableTreeNode mycommand = new DefaultMutableTreeNode(
//			new HPMenuItem(HPItem.TYPE_MENU_ITEM_CMD, "播放音乐", "cmd://playMusic?loop=true&num=2", ""));

	// 定义需要被拖动的TreePath
	TreePath movePath;
	public final static NodeEditPanel emptyNodeEditPanel = new NodeEditPanel() {
		@Override
		public void init(final MutableTreeNode data, JTree tree) {
		}
	};
	
	private Icon getSampleIcon(){
		return loadImg("hc/server/ui/design/res/gift_24.png");
	}
	
	private NodeEditPanel nodeEditPanel = emptyNodeEditPanel;
	JButton sampleButton = new JButton("Sample", getSampleIcon());
	JButton saveButton = new JButton("Save", loadImg("hc/server/ui/design/res/save_24.png"));
	JButton deployButton = new JButton("Deploy", loadImg("hc/server/ui/design/res/deploy_24.png"));
	JButton undeployButton = new JButton("Undeploy", loadImg("hc/server/ui/design/res/undeploy_24.png"));
	JButton newButton = new JButton("New", loadImg("hc/server/ui/design/res/new_24.png"));
	JButton shareToButton = new JButton("Share to", loadImg("hc/server/ui/design/res/shareout_24.png"));
	JButton shareFromButton = new JButton("Share from", loadImg("hc/server/ui/design/res/sharein_24.png"));
	DefaultMutableTreeNode selectedNode;
	JPanel editPanel = new JPanel();
	private MenuManager mm = new MenuManager();
	private NodeEditPanelManager nm = new NodeEditPanelManager();
	
	public static ImageIcon iconMenuItem = loadImg("hc/server/ui/design/res/menuitem.png");

	public static ImageIcon iconMenu = loadImg("hc/server/ui/design/res/menu.png");

	public static ImageIcon iconRoot = loadImg("hc/server/ui/design/res/root.png");
	
	public static ImageIcon iconDel = loadImg("hc/server/ui/design/res/del.png");
	
	public static ImageIcon iconSaveAs = loadImg("hc/server/ui/design/res/save_16.png");
	
	public static ImageIcon iconShareRoot = loadImg("hc/server/ui/design/res/share.png");
	
	public static ImageIcon iconShareRBFolder = loadImg("hc/server/ui/design/res/rb_folder.png");
	
	public static ImageIcon iconShareRB = loadImg("hc/server/ui/design/res/jruby.png");
	
	public static ImageIcon iconJar = loadImg("hc/server/ui/design/res/jar.png");
	
	public static ImageIcon iconJarFolder = loadImg("hc/server/ui/design/res/jar_folder.png");
			
	public static ImageIcon iconEventFolder = loadImg("hc/server/ui/design/res/radar.png");
	
	public static ImageIcon iconEventItem = loadImg("hc/server/ui/design/res/radar_on.png");
	
	private void changeTreeNodeContext(DefaultMutableTreeNode _node, HPItemContext context){
		((HPNode)_node.getUserObject()).setContext(context);
		
		final int size = _node.getChildCount();
		for (int i = 0; i < size; i++) {
			changeTreeNodeContext((DefaultMutableTreeNode)_node.getChildAt(i), context);
		}
	}
	
	final HPItemContext itemContext;
	
	public static File switchHar(File jar, File har){
		if(jar.exists()){
			ThirdlibManager.copy(jar, har);
			jar.delete();
		}
		return har;
	}
	
	public Designer() {
		setTitle("Mobile UI Designer");
		
		setIconImage(App.SYS_LOGO);
		setName("Designer");
		ComponentListener cl = new LocationComponentListener();
		
		addComponentListener(cl);
		
		shareFolders[0] = createShareJRubyFolder();
		shareFolders[1] = createShareJarFolder();
		
		
		J2SEContext.appendTitleJRubyVer(this);
		
		itemContext = new HPItemContext();
		itemContext.modified = this;
		
		tree = new JTree(root);
		tree.getSelectionModel().setSelectionMode(  
                TreeSelectionModel.SINGLE_TREE_SELECTION); 
		model = (DefaultTreeModel) tree.getModel();		
		
		File har = switchHar(new File(MY_EDIT_PROJ), new File(MY_EDIT_PROJ_HAR));
		Map<String, Object> map = HCjar.loadJar(har, true);
		loadNodeFromMap(map);
		
		
		final ActionMap actionMap = tree.getActionMap();
		actionMap.put( "cut", null );
		actionMap.put( "copy", null );
		actionMap.put( "paste", null );
		
//		DragSource dragSource = DragSource.getDefaultDragSource();
//		dragSource.createDefaultDragGestureRecognizer(tree, DnDConstants.ACTION_NONE, null);
		
		tree.setCellRenderer(new NodeTreeCellRenderer());
		
//		自定义树节点，选中颜色
//		DefaultTreeCellRenderer cellRenderer =  
//                (DefaultTreeCellRenderer)tree.getCellRenderer();
//		cellRenderer.setBackgroundNonSelectionColor(Color.white);  
//		cellRenderer.setBackgroundSelectionColor(Color.yellow);  
//		cellRenderer.setBorderSelectionColor(Color.red);  
//        //设置选或不选时，文字的变化颜色  
//		cellRenderer.setTextNonSelectionColor(Color.black);  
//		cellRenderer.setTextSelectionColor(Color.blue);  

        
		// 获取JTree对应的TreeModel对象
        
		tree.setEditable(false);
		
		final Designer self = this;
		
		MouseListener ml = new MouseListener() {
			// 按下鼠标时候获得被拖动的节点
			public void mousePressed(MouseEvent e) {
				// 如果需要唯一确定某个节点，必须通过TreePath来获取。
				TreePath tp = tree.getPathForLocation(e.getX(), e.getY());
				if (tp != null) {
					movePath = tp;
				}
			}

			// 鼠标松开时获得需要拖到哪个父节点
			public void mouseReleased(MouseEvent e) {
				// 根据鼠标松开时的TreePath来获取TreePath
				TreePath tp = tree.getPathForLocation(e.getX(), e.getY());

//				Drag and Drop
//				if (tp != null && movePath != null) {
//					// 阻止向子节点拖动
//					if (movePath.isDescendant(tp) && movePath != tp) {
//						JOptionPane.showMessageDialog(this,
//								"目标节点是被移动节点的子节点，无法移动！", "非法操作",
//								JOptionPane.ERROR_MESSAGE);
//						return;
//					}
//					// 既不是向子节点移动，而且鼠标按下、松开的不是同一个节点
//					else if (movePath != tp) {
//						System.out.println(tp.getLastPathComponent());
//						// add方法可以先将原节点从原父节点删除，再添加到新父节点中
//						((DefaultMutableTreeNode) tp.getLastPathComponent())
//								.add((DefaultMutableTreeNode) movePath
//										.getLastPathComponent());
//						movePath = null;
//						tree.updateUI();
//					}
//				}
				
				if(tp == null){
					return;
				}
				
				Object obj = tp.getLastPathComponent();
				if (obj != null && (obj instanceof DefaultMutableTreeNode)) {
					selectedNode = (DefaultMutableTreeNode) obj;
				}else{
					selectedNode = null;
				}
				
				if (e.getButton() == MouseEvent.BUTTON3) {
					if(selectedNode != null){
						Object o = selectedNode.getUserObject();
						if (o instanceof HPNode) {
							jumpToNode(selectedNode);

							mm.popUpMenu(((HPNode) o).type, selectedNode, tree, e, self);
						}
					}
				}else if (e.getButton() == MouseEvent.BUTTON1) {
					if(selectedNode != null){
						Object o = selectedNode.getUserObject();
						if (o instanceof HPNode) {
							final HPNode nodeData = (HPNode) o;
							notifySelectNode(selectedNode, nodeData);
						}
					}
				}
			}

			@Override
			public void mouseClicked(MouseEvent e) {
			}

			@Override
			public void mouseEntered(MouseEvent e) {
			}

			@Override
			public void mouseExited(MouseEvent e) {
			}
		};

		// {
		// public void actionPerformed(ActionEvent event)
		// {
		// //获取选中节点
		// DefaultMutableTreeNode selectedNode
		// = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
		// //如果节点为空，直接返回
		// if (selectedNode == null) return;
		// //获取该选中节点的父节点
		// DefaultMutableTreeNode parent
		// = (DefaultMutableTreeNode)selectedNode.getParent();
		// //如果父节点为空，直接返回
		// if (parent == null) return;
		// //创建一个新节点
		// DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("新节点");
		// //获取选中节点的选中索引
		// int selectedIndex = parent.getIndex(selectedNode);
		// //在选中位置插入新节点
		// model.insertNodeInto(newNode, parent, selectedIndex + 1);
		// //--------下面代码实现显示新节点（自动展开父节点）-------
		// //获取从根节点到新节点的所有节点
		// TreeNode[] nodes = model.getPathToRoot(newNode);
		// //使用指定的节点数组来创建TreePath
		// TreePath path = new TreePath(nodes);
		// //显示指定TreePath
		// tree.scrollPathToVisible(path);
		// }
		// });

//		tree.addTreeSelectionListener(new TreeSelectionListener() {
//			@Override
//			public void valueChanged(TreeSelectionEvent e) {
//				DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
//
//				if (node == null)
//					return;
//
//				HPItem item = (HPItem)node.getUserObject();
//				notifySelectNode(item);
//			}
//		});
		tree.addMouseListener(ml);
		
		JPanel toolbarPanel = new JPanel();
		setModified(false);
		final Action saveAction = new AbstractAction() {
			public void actionPerformed(ActionEvent event) {
//				TreePath selectedPath = tree.getSelectionPath();
//				if (selectedPath != null) {
//					// 编辑选中节点
//					tree.startEditingAtPath(selectedPath);
//				}
				
				save();
			}
		};
		saveAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_MASK));
		saveButton.addActionListener(saveAction);
		saveButton.getActionMap().put("myAction", saveAction);
		saveButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
		        (KeyStroke) saveAction.getValue(Action.ACCELERATOR_KEY), "myAction");
		
		toolbarPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 5));
		
		//检查是否有新版本
		final String lastSampleVer = PropertiesManager.getValue(PropertiesManager.p_LastSampleVer, "1.0");
		if(StringUtil.higer(RootConfig.getInstance().getProperty(RootConfig.p_Sample_Ver), lastSampleVer)){
			sampleButton.setIcon(loadImg("hc/server/ui/design/res/giftnew_24.png"));
		}
		sampleButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				if(quitToNewProj(self) == false){
					return;
				}
				
				try {
					final String url = "http://homecenter.mobi/download/sample.har";
					Map<String, Object> map = HCjar.loadJar(url);
					if(map.isEmpty()){
						JPanel panel = new JPanel();
						panel.add(new JLabel("<html>Sorry, Load sample har from remote server error." +
								"<BR>please try after a minute</html>", App.getSysIcon(App.SYS_ERROR_ICON), SwingConstants.LEFT));
						App.showCenterPanel(panel, 0, 0, "Network Error", false, null, null, null, self, true, false);
						return;
					}
					
					if(checkLoadVer(map) == false){
						return;
					}
					
					loadNodeFromMap(map);
					setModified(true);
					showHCMessage("Success load sample from server.", "Sample OK", self, true);
					
					sampleButton.setIcon(getSampleIcon());
					
					PropertiesManager.setValue(PropertiesManager.p_LastSampleVer, 
							RootConfig.getInstance().getProperty(RootConfig.p_Sample_Ver));
					PropertiesManager.saveFile();
					
					if(PropertiesManager.isTrue(PropertiesManager.p_SampleDeployNotify) == false){
						PropertiesManager.setValue(PropertiesManager.p_SampleDeployNotify, IConstant.TRUE);
						PropertiesManager.saveFile();

						JPanel panel = new JPanel();
						panel.add(new JLabel("Sample lib will work for mobile after click 'Deploy' button.", 
								App.getSysIcon(App.SYS_INFO_ICON), SwingConstants.LEFT));
						App.showCenterPanel(panel, 0, 0, "Deploy me later", false, null, null, null, self, true, false);
					}
				} catch (Exception e1) {
					JOptionPane.showMessageDialog(self, "Error download sample.har, " +
							"please try after few minutes.", "Error Sample", 
							JOptionPane.ERROR_MESSAGE);
				}
			}
		});
		sampleButton.setToolTipText("<html>This is tutorial and demo, tell me how to design my project," +
				"<BR>saving it as my project is free.</html>");
		toolbarPanel.add(sampleButton);
		newButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				if(quitToNewProj(self) == false){
					return;
				}
				
				final Object userObject = buildInitRoot();
				
				notifySelectNode(root, (HPNode)userObject);
				deployButton.setEnabled(false);
				tree.updateUI();
			}
		});
		newButton.setToolTipText("<html>init the curr project, ready to create new items for my project." +
				"</html>");
		toolbarPanel.add(newButton);
		
		saveButton.setToolTipText("<html>it has no effect on deployed project.</html>");
		toolbarPanel.add(saveButton);
		
		deployButton.setToolTipText("<html>when mobile login, these menu will display to mobile, " +
				"instead of PC screen.<BR>before deploy project, please saving first.</html>");
		deployButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				PropertiesManager.setValue(PropertiesManager.p_IsMobiMenu, IConstant.TRUE);
				PropertiesManager.saveFile();
				
				ThirdlibManager.copy(new File(MY_EDIT_PROJ_HAR), new File(MY_DEPLOY_PROJ_HAR));
				
				ServerUIUtil.useMainCanvas = true;
				undeployButton.setEnabled(true);
				ServerUIUtil.initBackServer();
				
				showHCMessage("Successful deploy project, " +
						"mobile will access this resources.", "Deploy OK", self, true);
//						JOptionPane.INFORMATION_MESSAGE);
			}
		});
		toolbarPanel.add(deployButton);
		if(!ServerUIUtil.useMainCanvas){
			undeployButton.setEnabled(false);
		}
		undeployButton.setToolTipText("when mobile login, only PC screen is accessed");
		undeployButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				PropertiesManager.setValue(PropertiesManager.p_IsMobiMenu, IConstant.FALSE);
				PropertiesManager.saveFile();
				
				new File(MY_DEPLOY_PROJ).delete();
				new File(MY_DEPLOY_PROJ_HAR).delete();
				
				ServerUIUtil.useMainCanvas = false;
				undeployButton.setEnabled(false);
				ServerUIUtil.initBackServer();
				
				showHCMessage("Successful undeploy project, " +
						"mobile will access PC screen only.", "Undeploy OK", self, true);
//				JOptionPane.showMessageDialog(this, "Successful undeploy project, " +
//						"mobile will access PC screen only.", "Undeploy OK", 
//						JOptionPane.INFORMATION_MESSAGE);
			}
		});
		toolbarPanel.add(undeployButton);
		shareToButton.setToolTipText("share this project to my friends by a har file");
		shareToButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				if(self.isModified()){
					JPanel panel = new JPanel();
					panel.add(new JLabel("Save this project before share?", App.getSysIcon(App.SYS_QUES_ICON), SwingConstants.LEFT));
					App.showCenterPanel(panel, 0, 0, "save it before", true, null, new ActionListener() {
						@Override
						public void actionPerformed(ActionEvent e) {
							if(save() == false){
								return;
							}
							shareTo();
						}
					}, new ActionListener() {
						@Override
						public void actionPerformed(ActionEvent e) {
							shareTo();
						}
					}, self, true, false);
				}else{
					shareTo();
				}
			}
		});
		toolbarPanel.add(shareToButton);
		if(new File(MY_EDIT_PROJ_HAR).exists() == false){
			deployButton.setEnabled(false);
			shareToButton.setEnabled(false);
		}
		shareFromButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				File file = FileSelector.selectImageFile(self, FileSelector.HAR_FILTER, true);
				if(file != null){
					Map map = HCjar.loadJar(file, true);
					if(map.isEmpty()){
						JOptionPane.showMessageDialog(self, "Error import project from har file.", 
								"Error share from", JOptionPane.ERROR_MESSAGE);
					}else{
						if(checkLoadVer(map) == false){
							return;
						}

						loadNodeFromMap(map);
						
						setModified(true);
						showHCMessage("Successful import project from har file.", 
								"Success share from", self, true);
//						JOptionPane.showMessageDialog(this, "Successful import project from jar file.", 
//									"Success share from", JOptionPane.INFORMATION_MESSAGE);
					}
				}
			}
		});
		shareFromButton.setToolTipText("share project from my friends by a har file");
		toolbarPanel.add(shareFromButton);
		
		JPanel treePanel = new JPanel();
		treePanel.setBorder(new TitledBorder("Select Area :"));
		final JScrollPane scrollPane = new JScrollPane(tree);
		treePanel.setLayout(new BorderLayout());
		treePanel.add(scrollPane, BorderLayout.CENTER);
		
		editPanel.setLayout(new BorderLayout());
		editPanel.add(nodeEditPanel);
		
		JSplitPane panelSubMRInfo = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
				treePanel, editPanel);
		panelSubMRInfo.setDividerLocation(300);

		setLayout(new BorderLayout());
		add(panelSubMRInfo, BorderLayout.CENTER);
		
		JPanel toolbarLeftPanel = new JPanel();
		toolbarLeftPanel.setLayout(new BorderLayout());
		toolbarLeftPanel.add(toolbarPanel, BorderLayout.WEST);
		add(toolbarLeftPanel, BorderLayout.NORTH);
		
		setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				if(self.isModified()){
					int out = modifyNotify();
		    		if(out == 0){
		    			dispose();
		    		}
				}else{
					dispose();
				}
			}
		});

		setPreferredSize(new Dimension(1024, 768));
		pack();
		
		if(LocationComponentListener.hasLocation(this) && LocationComponentListener.loadLocation(this)){
			setVisible(true);
		}else{
			App.showCenter(this);
		}
	}

	private void loadNodeFromMap(Map<String, Object> map) {
		delAllChildren();
		
		DefaultMutableTreeNode mainMenuNode = HCjar.toNode(map, root, shareFolders);
		appendShareTop();
		
		changeTreeNodeContext(root, itemContext);
		
		DefaultMutableTreeNode childNode;
		if(mainMenuNode != null && mainMenuNode.getChildCount() > HCjar.SKIP_SUB_MENU_ITEM_NUM){
			childNode = (DefaultMutableTreeNode)mainMenuNode.getChildAt(HCjar.SKIP_SUB_MENU_ITEM_NUM);
		}else{
			childNode = (DefaultMutableTreeNode)mainMenuNode.getChildAt(0);
		}
		jumpToNode(childNode);
		notifySelectNode(childNode, (HPNode)childNode.getUserObject());
	}

	public void addNode(DefaultMutableTreeNode newNode) {
		changeTreeNodeContext(newNode, itemContext);
		
		selectedNode.add(newNode);
		// --------下面代码实现显示新节点（自动展开父节点）-------
		TreeNode[] nodes = model.getPathToRoot(newNode);
		TreePath path = new TreePath(nodes);
		tree.setSelectionPath(path);
//				tree.setExpandsSelectedPaths(true); 
		tree.scrollPathToVisible(path);
		tree.updateUI();
		setModified(true);
		
		notifySelectNode(newNode, (HPNode)newNode.getUserObject());
	}
	
	public void saveAs(){
		Object userobj = selectedNode.getUserObject();
		if(userobj instanceof HCShareFileResource){
			File saveTo = FileSelector.selectImageFile(this, FileSelector.JAR_FILTER, false);
			if(saveTo != null){
				if(saveTo.toString().endsWith(".jar")){
					
				}else{
					saveTo = new File(saveTo.getPath() + ".jar");
				}
				
				FileOutputStream fos = null;
				try{
					fos = new FileOutputStream(saveTo);
					fos.write(((HCShareFileResource)userobj).content);
					fos.flush();
					fos.close();
					
					JPanel ok = new JPanel();
					try {
						ok.add(new JLabel("Successful save jar file!", new ImageIcon(ImageIO.read(ImageSrc.OK_ICON)), SwingConstants.LEFT));
					} catch (IOException e2) {
					}
					App.showCenterPanel(ok, 0, 0, "Save OK!", false, null, null, null, this, true, false);
				}catch (Exception e) {
					JPanel ok = new JPanel();
					try {
						ok.add(new JLabel("Error save jar file!", new ImageIcon(ImageIO.read(ImageSrc.CANCEL_ICON)), SwingConstants.LEFT));
					} catch (IOException e2) {
					}
					App.showCenterPanel(ok, 0, 0, "Save Error!", false, null, null, null, this, true, false);
					e.printStackTrace();
				}finally{
					try{
						fos.close();
					}catch (Exception e) {
						
					}
				}
			}
		}
	}

	public void delNode() {
		DefaultMutableTreeNode parent = (DefaultMutableTreeNode)selectedNode.getParent();
		model.removeNodeFromParent(selectedNode);
		setModified(true);
		selectedNode = null;
		
		jumpToNode(parent);
		notifySelectNode(parent, (HPNode)parent.getUserObject());
	}
	
	public TreeNode getCurrSelectedNode(){
		return selectedNode;
	}

	public void notifySelectNode(DefaultMutableTreeNode sNode, final HPNode nodeData) {
		selectedNode = sNode;
		
		NodeEditPanel nep = nm.switchNodeEditPanel(nodeData.type);
		editPanel.remove(nodeEditPanel);
		
		if(nep == null){
			nodeEditPanel = Designer.emptyNodeEditPanel;
		}else{
			nodeEditPanel = nep;
		}
		
		nodeEditPanel.init(sNode, tree);
		
		editPanel.add(nodeEditPanel);
		editPanel.validate();
		editPanel.revalidate();
		editPanel.repaint();
	}

	@Override
	public boolean isModified() {
		return isModified;
	}

	@Override
	public void setModified(boolean modified) {
		J2SEContext.refreshActionMS(false);
		this.isModified = modified;
		saveButton.setEnabled(modified);
		deployButton.setEnabled(!modified);
	}

	/**
	 * 
	 * @return 返回0表示，忽略修改
	 */
	private int modifyNotify() {
		final byte[] isClose = {-2};
		JPanel panel = new JPanel();
		panel.add(new JLabel("project is modified and not save! close now?"));
		App.showCenterPanel(panel, 0, 0, "close project now?", true, null, new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				isClose[0] = 0;
			}
		}, new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				isClose[0] = -1;
			}
		}, this, true, false);
		
		return isClose[0];
	}

	private void jumpToNode(DefaultMutableTreeNode node) {
		TreeNode[] nodes = model.getPathToRoot(node);
		TreePath path = new TreePath(nodes);
		tree.setSelectionPath(path);
	}
	
	private void showHCMessage(final String message, final String title, JFrame frame, boolean model){
		JPanel panel = new JPanel();
		try {
			panel.add(new JLabel(message, new ImageIcon(ImageIO.read(ImageSrc.OK_ICON)), SwingConstants.LEFT));
		} catch (IOException e2) {
		}
		App.showCenterPanel(panel, 0, 0, title, false, null, null, null, frame, model, false);
	}

	private boolean quitToNewProj(final Designer self) {
		if(self.isModified() && modifyNotify() != 0){
			return false;
		}
		
		self.setModified(false);
		return true;
	}

	private Object buildInitRoot() {
		DefaultMutableTreeNode tnode = createNewRoot();
		
		delAllChildren();
		
		final Object userObject = tnode.getUserObject();
		root.setUserObject(userObject);

		changeTreeNodeContext(root, itemContext);
		
		appendShareTop();
		
		return userObject;
	}

	private void delAllChildren() {
		root.removeAllChildren();
		for (int i = 0; i < shareFolders.length; i++) {
			shareFolders[i].removeAllChildren();
		}
	}

	private void appendShareTop() {
		//加载共享库结点
		HPShareRoot sr = new HPShareRoot(HPNode.MASK_SHARE_TOP, "resources");
		DefaultMutableTreeNode shareRoot = new DefaultMutableTreeNode(sr);
		root.add(shareRoot);
		
		//加挂公用JRuby库
		for (int i = 0; i < shareFolders.length; i++) {
			shareRoot.add(shareFolders[i]);	
		}
	}

	/**
	 * 返回true，表示继续。
	 * @param map
	 * @return
	 */
	private boolean checkLoadVer(Map<String, Object> map) {
		String[] sample_ver = {(String)map.get(HCjar.HOMECENTER_VER), 
				(String)map.get(HCjar.JRE_VER), (String)map.get(HCjar.JRUBY_VER)};
		String[] curr_ver = {J2SEContext.getVersion(), String.valueOf(App.getJREVer()), 
				PropertiesManager.getValue(PropertiesManager.p_jrubyJarVer)};
		boolean[] isSampleHigh = {false, false, false};
		boolean isHigh = false;
		for (int i = 0; i < sample_ver.length; i++) {
			if(sample_ver[i] != null){
				if(StringUtil.higer(sample_ver[i], curr_ver[i])){
					isSampleHigh[i] = true;
					isHigh = true;
				}
			}else{
				sample_ver[i] = "unknow ver";
			}
		}

		
		if(isHigh){
			String sample = "";
			String curr = "";
			
			String[] whatVer = {"HomeCenter Ver", "JRE Ver", "JRuby Ver"};
			for (int i = 0; i < isSampleHigh.length; i++) {
				if(isSampleHigh[i] == false){
					continue;
				}
				boolean isNotFirst = (sample.length() > 0);
				sample += whatVer[i] + ":" + sample_ver[i] + (isNotFirst?",   ":"");
				curr += whatVer[i] + ":" + (isSampleHigh[i]?
						("<font style='color:red'>" + curr_ver[i] + "</font>"):curr_ver[i]) + (isNotFirst?",":"");
				
				if(isNotFirst){
					for (int j = 0, addNum = 3 + (sample_ver[i].length() - curr_ver[i].length()); 
							j < addNum; j++) {
						curr += " ";
					}
				}
			}
			
			sample = "Import Ver : [" + sample + "]";
			curr   = "System Ver : [" + curr + "]";
			final boolean[] isContinue = {true};
			JPanel panel = new JPanel();
			panel.add(new JLabel("<html><body>" + sample + "<BR>" + curr + "<BR><BR>" +
					"some data may ignore, or run error.<BR><BR>Continue any more?" + 
					(isSampleHigh[0]?("<BR>please 'enable auto upgrade' to upgrade HomeCenter Ver"):"") 
					+ "</body></html>", 
					App.getSysIcon(App.SYS_WARN_ICON), SwingConstants.LEFT));
			App.showCenterPanel(panel, 0, 0, "Version warning", true, null, new ActionListener() {
				
				@Override
				public void actionPerformed(ActionEvent e) {
				}
			}, new ActionListener() {
				
				@Override
				public void actionPerformed(ActionEvent e) {
					isContinue[0] = false;
				}
			}, this, true, false);
			
			if(isContinue[0] == false){
				return false;
			}
		}
		return true;
	}

	private boolean save() {
		try{
			HCjar.toJar(HCjar.toMap(root, shareFolders), new File(MY_EDIT_PROJ_HAR));
			
			tree.updateUI();
			
			setModified(false);
			
			deployButton.setEnabled(true);
			shareToButton.setEnabled(true);
			
			return true;
		}catch (NodeInvalidException e) {
			final DefaultMutableTreeNode node1 = e.node;
			jumpToNode(node1);
			notifySelectNode(node1, (HPNode)node1.getUserObject());
			
			JPanel panel = new JPanel();
			String name1 = ((HPNode)node1.getUserObject()).name;
			panel.add(new JLabel("<html><body>" + e.getDesc() + "</body></html>", 
					App.getSysIcon(App.SYS_ERROR_ICON), SwingConstants.LEFT));
			App.showCenterPanel(panel, 0, 0, "Error Node", false, null, null, null, this, true, false);
			
			return false;
		}
	}

	private void shareTo() {
		File file = FileSelector.selectImageFile(this, FileSelector.HAR_FILTER, false);
		if(file != null){
			if(file.toString().endsWith(".har")){
				
			}else{
				file = new File(file.getPath() + ".har");
			}
			
			if(ThirdlibManager.copy(new File(MY_EDIT_PROJ_HAR), file)){
				showHCMessage("Successful export project to har file.", 
						"Success share to", this, true);
//						JOptionPane.showMessageDialog(this, "Successful export project to jar file.", 
//								"Success share to", JOptionPane.INFORMATION_MESSAGE);
			}else{
				JOptionPane.showMessageDialog(this, "Error export project to har file.", 
						"Error share to", JOptionPane.ERROR_MESSAGE);
			}
		}
	}

}

class NodeTreeCellRenderer extends DefaultTreeCellRenderer {
	NodeTreeCellRenderer() {
	}

	public Component getTreeCellRendererComponent(JTree tree, Object value,
			boolean selected, boolean expanded, boolean leaf, int row,
			boolean hasFocus) {
		Component compo = super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
		Object o = ((DefaultMutableTreeNode) value).getUserObject();
		if (o instanceof HPNode) {
			HPNode country = (HPNode) o;
			if (HPNode.isNodeType(country.type, HPNode.MASK_ROOT)) {
				((JLabel)compo).setIcon(Designer.iconRoot);
			} else if (HPNode.isNodeType(country.type, HPNode.MASK_MENU_ITEM)) {
				((JLabel)compo).setIcon(Designer.iconMenuItem);
			} else if (HPNode.isNodeType(country.type, HPNode.MASK_MENU)) {
				((JLabel)compo).setIcon(Designer.iconMenu);
			} else if (HPNode.isNodeType(country.type, HPNode.MASK_SHARE_TOP)) {
				((JLabel)compo).setIcon(Designer.iconShareRoot);
			} else if (HPNode.isNodeType(country.type, HPNode.MASK_SHARE_RB_FOLDER)) {
				((JLabel)compo).setIcon(Designer.iconShareRBFolder);
			} else if (HPNode.isNodeType(country.type, HPNode.MASK_SHARE_RB)) {
				((JLabel)compo).setIcon(Designer.iconShareRB);
			} else if (country.type == HPNode.MASK_RESOURCE_FOLDER_JAR) {
				((JLabel)compo).setIcon(Designer.iconJarFolder);
			} else if (country.type == HPNode.MASK_RESOURCE_JAR) {
				((JLabel)compo).setIcon(Designer.iconJar);
			} else if (country.type == HPNode.MASK_EVENT_FOLDER) {
				((JLabel)compo).setIcon(Designer.iconEventFolder);
			} else if (country.type == HPNode.MASK_EVENT_ITEM) {
				((JLabel)compo).setIcon(Designer.iconEventItem);
			}
			((JLabel)compo).setText(country.toString());
		} else {
			((JLabel)compo).setIcon(null);
			((JLabel)compo).setText("" + value);
		}
		
		return compo;
	}
}

class LocationComponentListener implements ComponentListener {
	@Override
	public void componentShown(ComponentEvent e) {
	}
	
	@Override
	public void componentResized(ComponentEvent e) {
		saveLocation(e.getComponent());
	}
	
	@Override
	public void componentMoved(ComponentEvent e) {
		saveLocation(e.getComponent());
	}
	
	@Override
	public void componentHidden(ComponentEvent e) {
	}
	
	private void saveLocation(Component component){
		final String title = component.getName();
		final Rectangle r = component.getBounds();

//		System.out.println("saveLocation, x:" + r.x + ", y:" + r.y + ", w:" + r.width + ", h:" + r.height);

		PropertiesManager.setValue(title + PropertiesManager.p_WindowX, String.valueOf(r.x));
		PropertiesManager.setValue(title + PropertiesManager.p_WindowY, String.valueOf(r.y));
		PropertiesManager.setValue(title + PropertiesManager.p_WindowWidth, String.valueOf(r.width));
		PropertiesManager.setValue(title + PropertiesManager.p_WindowHeight, String.valueOf(r.height));
		
		PropertiesManager.saveFile();
	}
	
	public static boolean hasLocation(Component component){
		final String title = component.getName();
		return (PropertiesManager.getValue(title + PropertiesManager.p_WindowX) != null); 
	}
	
	public static boolean loadLocation(Component component){
		final String title = component.getName();
		try{
			component.setBounds(
					Integer.parseInt(PropertiesManager.getValue(title + PropertiesManager.p_WindowX)), 
					Integer.parseInt(PropertiesManager.getValue(title + PropertiesManager.p_WindowY)), 
					Integer.parseInt(PropertiesManager.getValue(title + PropertiesManager.p_WindowWidth)), 
					Integer.parseInt(PropertiesManager.getValue(title + PropertiesManager.p_WindowHeight)));
			return true;
		}catch (Throwable e) {
		}
		return false;
	}
}